<template>
  <div class='GeneratorForm'>
    <!--  预览对话框  -->
    <FormDialog :formData="formData" v-model="previewVisible" @previewFormVisible="(val)=>previewVisible=val"/>
    <el-row class="content">
      <el-col class="components" :span="6">
        <div class='ComponentsTab'>
          <el-tabs
              v-model="activeTabName"
              :stretch="true"
          >
            <el-tab-pane
                label="常用组件"
                name="common"
            >
              <el-scrollbar>
                <el-collapse v-model="collapseLabelsActiveName">
                  <el-collapse-item v-for="(items,index) in commonComponents" :key="index"
                                    :title="items[0].componentType" :name="items[0].componentType">
                    <draggable
                        :animation="340"
                        item-key="tag"
                        class="components-draggable"
                        :list="items"
                        :group="{ name: 'componentsGroup', pull: 'clone', put: false }"
                        :clone="cloneComponent"
                        :sort="false"
                        @end="onEnd"
                        chosenClass="common-choosen"
                        ghostClass="common-ghost"
                    >
                      <template #item="{ element }">
                        <div
                            class="components-item"
                            @click="addComponent(element)"
                        >

              <span class="components-icon">

                <ComponentsIcon :icon="element.tagIcon"/>
              </span>
                          <div class="components-body" :title="element.tag">
                            <div>
                              {{
                                element.tag
                              }}
                            </div>
                            <div>{{ element.label }}</div>
                          </div>
                        </div>
                      </template>
                    </draggable>
                  </el-collapse-item>
                </el-collapse>
              </el-scrollbar>
            </el-tab-pane>
            <el-tab-pane
                label="套件"
                name="custom"
            >
              <div style="margin-top: 12px;">
                <el-scrollbar>
                  <draggable
                      :animation="340"
                      item-key="tag"
                      class="components-draggable"
                      :list="_customMadeComponents"
                      :group="{ name: 'componentsGroup', pull: 'clone', put: false }"
                      :sort="false"
                      @end="onEnd"
                      chosenClass="common-choosen"
                      ghostClass="common-ghost"
                  >
                    <template #item="{ element }">
                      <div
                          class="components-item"
                          @click="addComponent(element)"
                      >

              <span class="components-icon">

                <ComponentsIcon :icon="element.tagIcon"/>
              </span>
                        <div class="components-body" :title="element.tag">
                          <div>
                            {{
                              element.tag
                            }}
                          </div>
                          <div>{{ element.label }}</div>
                        </div>
                      </div>
                    </template>
                  </draggable>
                </el-scrollbar>
              </div>
            </el-tab-pane>
          </el-tabs>
        </div>
      </el-col>
      <el-col class="design" :span="12">
        <div class="design-header">
          <el-button
              size="small"
              icon="delete"
              @click="empty"
          >清空
          </el-button>
          <el-button
              icon="view"
              type="primary"
              size="small"
              @click="previewShow"
          >预览
          </el-button>
        </div>
        <el-scrollbar class="center-scrollbar">
          <el-row
              class="center-board-row"
          >
            <el-form
                ref="form"
                :size="formConf.size"
                :label-position="formConf.labelPosition"
                :disabled="formConf.disabled"
                :label-width="formConf.labelWidth + 'px'"
            >
              <draggable
                  :fallbackTolerance="3"
                  chosenClass="drawing-board-chosen"
                  ghostClass="drawing-board-ghost"
                  ref="formItem"
                  item-key="formId"
                  class="drawing-board"
                  :list="drawingList"
                  :animation="340"
                  group="componentsGroup"
                  @end="onMianDragEnd"
                  @change="onMianDragChange"
              >
                <template #item="{ element,index }">
                  <draggable-item
                      style="padding: 0"
                      :key="index"
                      :drawing-list="drawingList"
                      :element="element"
                      :index="index"
                      :active-id="activeId"
                      :form-conf="formConf"
                      :put="shouldClone"
                      @activeItem="activeFormItem"
                      @copyItem="drawingItemCopy"
                      @deleteItem="drawingItemDelete"
                  />
                </template>
              </draggable>
              <el-empty
                  description="请从左侧拖拽添加组件"
                  v-show="!drawingList.length"
                  class="empty-info"
              >
              </el-empty>
            </el-form>
          </el-row>
        </el-scrollbar>
      </el-col>
      <el-col class="props" :span="6">
        <RightPanel
            :active-data="activeData"
            :form-conf="formConf"
            :show-field="!!drawingList.length"
            @update:updateActiveData="activeFormItem"
        />
      </el-col>
    </el-row>
  </div>
</template>
<script setup name='GeneratorForm'>
import draggable from "vuedraggable";
import draggableItem from "@/views/flow/createDirectly/generatorForm/DraggableItem";
import {
  CommonComponents,
  formConf
} from "@/views/flow/createDirectly/generatorForm/config.js";
import FormDialog from "@/views/flow/createDirectly/generatorForm/FormDialog";
import {
  addNextNumber,
  debounceWait,
  getDrawingList,
  getFormConf,
  isNotEmptyArray,
  saveDrawingList
} from "@/views/flow/tool.js";
import * as _ from 'lodash';
import flowStore from "@/views/flow/flowStore.js";
import ComponentsIcon from "@/views/flow/createDirectly/generatorForm/ComponentsIcon.vue";
import {ElMessageBox} from "element-plus";
import RightPanel from "@/views/flow/createDirectly/generatorForm/RightPanel";
import {customMadeComponents} from "@/views/flow/createDirectly/generatorForm/customMadeComponents/index.js";
const _customMadeComponents = ref(customMadeComponents)
const formConfInDB = getFormConf()
const props = defineProps({
  createApproverType: {
    type: String,
    default: () => {
      return ''
    }
  },
  conf: {
    type: Object,
    default: () => {
      return undefined
    }
  },
  tabName: {
    type: String,
    default: () => {
      return ''
    }
  },
})
let tempActiveData
let oldActiveId
const form = ref(null)
const formItem = ref(null)
const formIds = ref([])
const _formConf = ref(formConf)
const activeTabName = ref('common')
//复制现有流程，拖套件时，先存一份原流程的数据
const reuseExistingProcessesFormDataConf = ref(undefined)
const commonComponents = ref(CommonComponents)
const collapseLabels = ref(Object.keys(commonComponents.value))
const collapseLabelsActiveName = ref(collapseLabels.value[0])
const storageList = getDrawingList()
const drawingList = ref(Array.isArray(storageList) && storageList.length ? storageList : [])
const activeData = ref(drawingList[0])
const activeId = ref('')
const formData = ref({})
const previewVisible = ref(false)
const previewShow = () => {
  AssembleFormData()
  previewVisible.value = true
}
const AssembleFormData = () => {
  formData.value = {
    ..._formConf.value,
    fields: JSON.parse(JSON.stringify(drawingList.value))
  };
}
const empty = () => {
  ElMessageBox.alert("确定要清空所有组件吗",
      "提示",
      {
        dangerouslyUseHTMLString: true,
        type: "warning",
      })
      .then(() => {
        drawingList.value = []
        flowStore.clearPCondition()
        flowStore.clearPApprovers()
        flowStore.clearPStart()
      })
}
const onEnd = (obj,
               a) => {
  if (obj.from !== obj.to) {
    activeData.value = tempActiveData
  }
}
/**
 * 阻止表格中嵌套行容器
 * 定制组件不能添加子组件
 */
// .drawing-row-item —— 行容器的类名 ipad里面的组件才会带有
    // 直接拖拽的行容器 最外层含有.drawing-row-item
    // 定制组件 内部含有.drawing-row-item
    // const hasRow = target.classList.contains('.drawing-row-item') || target.querySelector('.drawing-row-item') !== null
    // const isRowContainer = ['布局容器', '表格/明细'].includes(target.innerText) //是阻止从左侧拖拽嵌套
    // const isCusFromLeft = target.classList.contains('custom-component')
const shouldClone = (to,
                     from,
                     target,
                     event,
                     conf) => {
      const targetConf = target._underlying_vm_
      const isRowContainer = conf.cmpType === 'common' && conf.rowType === 'layout'
      if (isRowContainer) return true
      if (conf.cmpType === 'custom') return false
      if (conf.rowType === 'table') {
        if (targetConf.layout === 'rowFormItem') return false
        if (isFilledPCon([targetConf.formId])) return false
      }
      return true
    }
const isFilledPCon = (formIds) => {
  //这里是取流程图的数据，暂时先注释
  /*const processCmp = this.$parent.$children.find(t => t.isProcessCmp)
  return processCmp && processCmp.isFilledPCon(formIds)*/
  return false
}
const checkColItem = (cmp) => {
  if (!cmp) return false
  const isPcon = !!flowStore.processConditions.find(t => t.formId == cmp.formId)
  return isPcon && isFilledPCon([cmp.formId])
}
const onMianDragChange = (obj) => {
  if ('added' in obj) {
    const target = obj.added.element
    if (target != undefined && 'explained' in target) {
      if (drawingList.value.length > 0) {
        drawingList.value = drawingList.value.filter((item,
                                                      index) => {
          return !('explained' in item) || target.renderKey == item.renderKey
        })
      }
    }
  }
}
const onMianDragEnd = (obj,
                       a) => {
  activeFormItem(drawingList.value[obj.newIndex])
}
const cloneChildrenOfRowFormItem = (rowFormItem,
                                    level) => {
  if (rowFormItem.children && rowFormItem.children.length) {
    const children = rowFormItem.children
    children.forEach((clone,
                      index) => {
      clone.formId = createFormId({item: clone})
      clone.renderKey = clone.formId + new Date().getTime() // 改变renderKey后可以实现强制更新组件
      if (!clone.layout) clone.layout = 'colFormItem'
      if (clone.layout === 'colFormItem') {
        clone.vModel = clone.vModel || `field${clone.formId}`
        clone.placeholder !== undefined &&
        (clone.placeholder += clone.label)
      } else if (clone.layout === 'rowFormItem') {
        // delete clone.label;
        clone.componentName = `row${clone.formId}`
        clone.gutter = _formConf.value.gutter
        const _level = level + 100 * index
        cloneChildrenOfRowFormItem(clone,
            _level)
      }
    })
  }
}
//复制现有流程，生成formId，重新拉套件处理
const createFormIdReuseExistingProcesses = ({item}) => {
  if (props.createApproverType == 'reuseExistingProcesses' && item && item.vModel &&
      reuseExistingProcessesFormDataConf.value && Array.isArray(reuseExistingProcessesFormDataConf.value['fields']) &&
      reuseExistingProcessesFormDataConf.value['fields'].length > 0) {
    let vModel = item.vModel
    let fnFindTarget = (arr) => {
      for (var i = 0; i < arr.length; i++) {
        if (arr[i]['vModel'] == vModel) {
          return arr[i].formId
          break
        }
        if (arr[i]['children'] && Array.isArray(arr[i]['children']) && arr[i]['children'].length > 0) {
          return fnFindTarget(arr[i]['children'])
        }
      }
    }
    return fnFindTarget(reuseExistingProcessesFormDataConf['fields'])
  }
}
const generatefId = () => {
  formIds.value = addNextNumber(formIds.value)
  return formIds.value[formIds.value.length - 1]
}
const createFormId = ({item}) => {
  let id = undefined
  //复制流程，并拉其他套件的处理，已有节点，保留节点权限
  if (props.createApproverType == 'reuseExistingProcesses') {
    let fid = createFormIdReuseExistingProcesses({item})
    if (fid) {
      id = fid.toString()
    } else {
      //避免重复
      id = (Number(generatefId()) + 500).toString()
    }
  } else {
    id = generatefId()
        .toString()
  }
  return id
}
const getSameTagCmpNum = (tag) => {
  return drawingList.value.reduce((count,
                                   item) => {
        if (item.children) {
          return count + item.children.reduce((c,
                                               t) => {
                return t.tag === tag ? c + 1 : c
              },
              0)
        }
        return item.tag === tag ? count + 1 : count
      },
      0)
}
const createCmpLabel = (cmp) => {
  const len = getSameTagCmpNum(cmp.tag)
  return len ? cmp.label + len : cmp.label
}
const cloneComponent = (origin) => {
  // const clone = JSON.parse(JSON.stringify(origin));
  const clone = _.cloneDeep(origin)
  clone.formId = createFormId({item: clone})
  clone.renderKey = clone.formId + new Date().getTime() // 改变renderKey后可以实现强制更新组件
  if (!clone.layout) clone.layout = 'colFormItem'
  if (clone.layout === 'colFormItem') {
    clone.label = createCmpLabel(clone)
    clone.vModel = clone.vModel || `field${clone.formId}`
    clone.placeholder !== undefined && (clone.placeholder += clone.label)
    tempActiveData = clone
  } else if (clone.layout === 'rowFormItem') {
    if (clone.rowType === 'table') {
      clone.vModel = clone.vModel || `field${clone.formId}`
    }
    // delete clone.label;
    clone.componentName = `row${clone.formId}`
    clone.gutter = _formConf.value.gutter
    cloneChildrenOfRowFormItem(clone,
        100)
    tempActiveData = clone
  }
  return tempActiveData
}
const drawingItemDelete = (index,
                           parent) => {
  flowStore.delPCondition(parent[index].formId)
      .then(() => {
        parent.splice(index,
            1)
        const len = drawingList.value.length
        if (len) {
          activeFormItem(drawingList.value[len - 1])
        }
      })
}
const createIdAndKey = (item) => {
  item.formId = createFormId({item})
  item.renderKey = clone.formId + new Date().getTime()
  if (item.layout === 'colFormItem') {
    item.vModel = item.vModel || `field${item.formId}`
  } else if (item.layout === 'rowFormItem') {
    item.componentName = `row${item.formId}`
  }
  if (Array.isArray(item.children)) {
    item.children = item.children.map(childItem =>
        createIdAndKey(childItem)
    )
  }
  return item
}
const drawingItemCopy = (item,
                         parent) => {
  let clone = JSON.parse(JSON.stringify(item))
  clone = createIdAndKey(clone)
  parent.push(clone)
  activeFormItem(clone)
}
const activeFormItem = (element) => {
  const component = drawingList.value.find((item,
                                            index) => {
    return 'explained' in item
  })
  if (!component && _formConf.value.hasOwnProperty('kit')) {
    delete _formConf.value.kit
  }
  if (element) {
    activeData.value = element
    activeId.value = element.formId
    //替换drawingList中的element
    if (drawingList.value.length > 0) {
      drawingList.value = drawingList.value.map(item => {
        if (isNotEmptyArray(item.children)) {
          item.children = item.children.map(childItem => {
            if (childItem.formId === element.formId) {
              return element
            }
            return childItem
          })
        }
        if (item.formId === element.formId) {
          return element
        }
        return item
      })
    }
  }
}
const addComponent = (target) => {
  // 新增之前将套件清除
  if (target != undefined && 'explained' in target) {
    if (drawingList.value.length > 0) {
      drawingList.value = drawingList.value.filter((item,
                                                    index) => {
        return !('explained' in item)
      })
    }
  }
  const clone = cloneComponent(target)
  drawingList.value.push(clone)
  activeFormItem(clone)
}
const handlerListChange = (val) => {
  flowStore.clearPApprovers();// 清除所有条件 重新检测赋值
  flowStore.clearPCondition();// 清除所有条件 重新检测赋值
  flowStore.clearPStart();// 清除所有条件 重新检测赋值
  const canUsedAsPCon = (conf,
                         parent) => {
    if (parent && parent.rowType === 'table') return false
    if (!conf.proCondition) return false
    return true
  }
  const loop = (data,
                parent) => {
    if (!data) return
    Array.isArray(data.children) && data.children.forEach(child => loop(child,
        data))
    if (Array.isArray(data)) {
      data.forEach(loop)
    } else {
      canUsedAsPCon(data,
          parent)
          ? flowStore.addPCondition(data)
          : flowStore.delPCondition(data.formId)
    }
  }
  loop(drawingList.value)
  saveDrawingList(drawingList.value)
  flowStore.updateFormItemList(drawingList.value)
  // 如果是目标部门,增加审批节点的选项(增加目标部门主管)
  let fcTargetDeptSelect = null
  drawingList.value.forEach((item,
                             index) => {
    if (item.tag == 'fc-target-dept-select') {
      fcTargetDeptSelect = item
    }
    if ('children' in item) {
      item.children.forEach((res) => {
        if (res.tag == 'fc-target-dept-select') {
          fcTargetDeptSelect = res
        }
      })
    }
  })
  if (fcTargetDeptSelect) {
    flowStore.addPApprovers(fcTargetDeptSelect)
  }
  // 如果是目标人员,增加审批节点的选项(增加目标人员主管)
  let fcTargetUserSelect = null
  drawingList.value.forEach((item,
                             index) => {
    if (item.tag == 'fc-target-user-select') {
      fcTargetUserSelect = item
    }
    if ('children' in item) {
      item.children.forEach((res) => {
        if (res.tag == 'fc-target-user-select') {
          fcTargetUserSelect = res
        }
      })
    }
  })
  if (fcTargetUserSelect) {
    flowStore.addPApprovers(fcTargetUserSelect)
  }
  drawingList.value.forEach((item,
                             index) => {
    if (item.tag == 'fixed-user-select') {
      flowStore.addPApprovers(item)
    }
    if ('children' in item) {
      item.children.forEach((res) => {
        if (res.tag == 'fixed-user-select') {
          flowStore.addPApprovers(res)
        }
      })
    }
  })
}
watch(() => 'activeData.label',
    (val,
     oldVal) => {
      if (
          activeData.value.placeholder === undefined ||
          !activeData.value.tag ||
          oldActiveId !== activeId.value
      ) {
        return
      }
      activeData.value.placeholder =
          activeData.value.placeholder.replace(oldVal,
              '') + val
    })
watch(() => activeId,
    (val,
     oldVal) => {
      oldActiveId = val
    },
    {immediate: true})
let afterDrawingChange = undefined
watch(drawingList,
    (val) => {
      formIds.value = []
      if (!val) {
        return
      }
      if (!afterDrawingChange) {
        afterDrawingChange = debounceWait(handlerListChange,
            400) // 使用了deep 所以刷新会比较频繁
      }
      formIds.value = val.map((item) => {
        return item.formId
      })
      val.forEach((child) => {
        if (isNotEmptyArray(child.children)) {
          child.children.forEach((res) => {
            formIds.value.push(res.formId)
          })
        }
      })
      afterDrawingChange()
    },
    {
      deep: true,
      immediate: true
    })
/**
 * 供父组件使用 获取表单JSON
 */
const getData = () => {
  return new Promise((resolve,
                      reject) => {
    if (drawingList.value.length === 0) {
      reject({
        msg: '表单不允许为空',
        target: props.tabName
      })
      return
    }
    AssembleFormData();
    resolve({
      formData: formData.value,
      target: props.tabName
    })
  })
}
onMounted(() => {
  if (typeof props.conf === 'object' && props.conf !== undefined) {
    drawingList.value = props.conf.fields
    _formConf.value = JSON.parse(JSON.stringify(props.conf))
    if (props.createApproverType == 'reuseExistingProcesses') {
      reuseExistingProcessesFormDataConf.value = JSON.parse(JSON.stringify(_formConf.value))
    }
  } else {
    const drawingListInDB = getDrawingList()
    const hasStorage = Array.isArray(drawingListInDB) && drawingListInDB.length > 0
    drawingList.value = hasStorage ? drawingListInDB : []
    formConfInDB && (_formConf.value = formConfInDB)
  }
  if (isNotEmptyArray(drawingList.value)) {
    activeFormItem(drawingList.value[0])
  }
})
defineExpose({
  getData
});
</script>
<style scoped lang='scss'>
@import 'item.scss';
.GeneratorForm {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  overflow: hidden;
  .dragChosenCssExtend {
    opacity: .8;
    background: #fff !important;
    display: flex;
    flex-direction: row;
    align-items: center;
    color: #000 !important;
    border-radius: 6px;
    cursor: move;
  }
  .dragGhostCssExtend {
    @extend .dragChosenCssExtend;
    opacity: 1;
    border: 1px dashed rgb(64, 158, 255);
    font-size: 12px !important;
    font-weight: normal !important;
    cursor: move;
  }
  .content {
    width: 100%;
    height: 100%;
    overflow: hidden;
    .components, .design, .props {
      overflow: hidden;
      overflow-y: auto;
    }
    .components {
      height: 100%;
      background: #ffffff;
      border: 1px solid #eee;
      border-top: 0;
      .ComponentsTab {
        width: 100%;
        height: 100%;
        overflow: hidden;
        display: flex;
        flex-direction: column;
        justify-content: flex-start;
        align-items: flex-start;
        .el-tabs {
          width: 100%;
          height: 100%;
          overflow: hidden;
          display: flex;
          flex-direction: column;
          justify-content: flex-start;
          align-items: flex-start;
          :deep(.el-tabs__content) {
            width: 100%;
            flex: 1;
            order: 2;
            overflow: hidden;
            display: flex;
            flex-direction: column;
            justify-content: flex-start;
            align-items: flex-start;
            .el-collapse-item__header {
              text-indent: 12px;
            }
            .el-tab-pane {
              width: 100%;
              flex: 0 0 100%;
              overflow: hidden;
            }
            [class^=el-collapse] {
              border: none !important;
            }
          }
          :deep(.el-tabs__header) {
            width: 100%;
            flex: 0;
            order: 1;
            margin: 0;
            .el-tabs__nav-wrap {
              .el-tabs__item {
                height: 51px;
              }
            }
          }
        }
        .components-draggable {
          padding: 0 12px;
          cursor: pointer;
          display: flex;
          flex-wrap: wrap;
          justify-content: space-between;
          align-items: center;
          gap: 8px;
          .components-item {
            flex: 0 1 48%;
            padding: 6px;
            border: 1px solid #d9d9d9;
            border-radius: 8px;
            font-size: 12px;
            color: rgba(17, 31, 44, 0.85);
            display: flex;
            flex-direction: row;
            align-items: center;
            gap: 12px;
            //左边组件栏，拖拽到中间时，样式
            &.common-ghost {
              @extend .draggableItemCommonCss;
              @extend .draggableItemCommonCss-ghost;
            }
            &.common-choosen {
              @extend .draggableItemCommonCss;
              @extend .draggableItemCommonCss-chosen;
            }
          }
        }
      }
    }
    .design {
      height: 100%;
      position: relative;
      display: flex;
      flex-direction: column;
      align-items: flex-start;
      justify-content: flex-start;
      background: #f5f5f7;
      .design-header {
        padding: 12px;
        background: #fff;
        width: 100%;
        display: flex;
        flex-direction: row;
        justify-content: flex-end;
        align-items: center;
        z-index: 2;
        border: 1px solid #eee;
      }
      .empty-info {
      }
      & > .el-scrollbar.center-scrollbar {
        width: 100%;
        :deep(.el-scrollbar__view) {
          .center-board-row {
            width: 100%;
            height: 100%;
            .el-form {
              width: 100%;
              height: 100%;
              padding: 36px;
              .drawing-board {
                background: #fff;
                border-radius: 12px;
                width: 100%;
                height: 100%;
                //左边组件，拖拽到中间，在中间呈现的样式
                .drawing-board-ghost {
                  @extend .draggableItemCommonCss;
                  @extend .draggableItemCommonCss-ghost;
                }
                .drawing-board-chosen {
                  @extend .draggableItemCommonCss;
                  @extend .draggableItemCommonCss-chosen;
                }
                .el-form-item__content {
                  display: flex;
                  flex-direction: column;
                  justify-content: flex-start;
                  align-items: flex-start;
                }
              }
            }
          }
        }
      }
    }
    .props {
      height: 100%;
      background: #ffffff;
    }
  }
}
</style>
